package com.m3839.sdk.common.http;

import com.m3839.sdk.common.http.listener.OnHttpRequestListener;
import com.m3839.sdk.common.http.ssl.HttpsHostnameVerifier;
import com.m3839.sdk.common.http.ssl.HttpsSSLSocketFactory;
import com.m3839.sdk.common.util.ThreadPoolUtil;

import org.json.JSONObject;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ConnectException;
import java.net.HttpURLConnection;
import java.net.ProtocolException;
import java.net.URL;
import java.net.URLEncoder;
import java.net.UnknownHostException;
import java.util.Map;
import java.util.concurrent.TimeoutException;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLHandshakeException;

/**
 * @author ChenBaoyang
 * @description: HttpDefaultManager
 * @date 2021/10/29 17:11
 */
public class HttpDefaultManager extends IHttpManager{


    private final static IHttpManager MANAGER = new HttpDefaultManager();

    private HttpDefaultManager() {}

    public static IHttpManager getManager() {
        return MANAGER;
    }

    @Override
    public void requestGet(final String baseUrl, Map<String, Object> params,
                           OnHttpRequestListener listener) {
        ThreadPoolUtil.execute(new Runnable() {
            @Override
            public void run() {
                HttpURLConnection urlConnection = null;
                try {
                    String url = baseUrl;
                    String paramStr = buildParams(params);
                    if (!"".equals(paramStr)) {
                        url = baseUrl + "?" + paramStr;
                    }

                    urlConnection = openURLConnection(url);
                    urlConnection.setRequestMethod(HTTP_METHOD_GET);
                    urlConnection.connect();


                    parseResponse(urlConnection, listener);

                } catch (Exception e) {
                    if (listener != null) {
                        listener.onResponseError(-4000, e.getMessage());
                    }
                }finally {
                    closeConnection(urlConnection);
                }
            }
        });
    }

    /**
     * get网络请求
     * @param baseUrl
     */
    @Override
    public void requestGet(final String baseUrl,
                                  Map<String, Object> params, Map<String, String> headers,
                                  OnHttpRequestListener listener){
        ThreadPoolUtil.execute(new Runnable() {
            @Override
            public void run() {
                HttpURLConnection urlConnection = null;
                try {
                    String url = baseUrl;
                    String paramStr = buildParams(params);
                    if (!"".equals(paramStr)) {
                        url = baseUrl + "?" + paramStr;
                    }

                    urlConnection = openURLConnection(url);

                    if(headers != null && !headers.isEmpty()) {

                        for (String key : headers.keySet()) {
                            urlConnection.setRequestProperty(key, headers.get(key));
                        }
                    }
                    urlConnection.setRequestMethod(HTTP_METHOD_GET);
                    urlConnection.connect();


                    parseResponse(urlConnection, listener);

                } catch (Exception e) {
                    if (listener != null) {
                        listener.onResponseError(-4000, e.getMessage());
                    }
                }finally {
                    closeConnection(urlConnection);
                }
            }
        });
    }

    @Override
    public void requestPost(String baseUrl, Map<String, Object> params,
                            OnHttpRequestListener listener) {
        requestPost(baseUrl, params, null, listener);
    }

    @Override
    public void requestPost(String baseUrl, Map<String, Object> params,
                            Map<String, String> headers, OnHttpRequestListener listener) {

        ThreadPoolUtil.execute(new Runnable() {
            @Override
            public void run() {
                HttpURLConnection urlConnection = null;
                try {
                    urlConnection = openURLConnection(baseUrl);
                    if(headers != null && !headers.isEmpty()) {

                        for (String key : headers.keySet()) {
                            urlConnection.setRequestProperty(key, headers.get(key));
                        }
                    }

                    urlConnection.setRequestMethod(HTTP_METHOD_POST);

                    /**
                     * 设置输入
                     */
                    urlConnection.setDoInput(true);
                    /**
                     * 设置输出
                     */
                    urlConnection.setDoOutput(true);

                    String newParams = buildParams(params);

                    //参数写入
                    DataOutputStream outputStream = new DataOutputStream(
                            urlConnection.getOutputStream()
                    );
                    outputStream.write(newParams.getBytes());
                    outputStream.flush();
                    outputStream.close();

                    //返回值解析
                    parseResponse(urlConnection, listener);


                } catch (Exception e) {
                    if(listener != null) {
                        if (e instanceof UnknownHostException ||
                                e instanceof ConnectException ||
                                e instanceof TimeoutException ||
                                e instanceof ProtocolException ||
                                e instanceof IOException ||
                                e instanceof EOFException ||
                                e instanceof SSLException ||
                                e instanceof SSLHandshakeException) {
                            listener.onResponseError(-4001, "网络连接异常");
                        }else  {
                            listener.onResponseError(-4000, e.getMessage());
                        }
                    }

                }finally {
                    closeConnection(urlConnection);
                }
            }
        });

    }

    @Override
    public void requestPost(String baseUrl, JSONObject jsonParam,
                            OnHttpRequestListener listener) {
        ThreadPoolUtil.execute(new Runnable() {
            @Override
            public void run() {
                HttpURLConnection urlConnection = null;
                try {
                    urlConnection = openURLConnection(baseUrl);
                    urlConnection.setRequestMethod(HTTP_METHOD_POST);

                    /**
                     * 设置输入
                     */
                    urlConnection.setDoInput(true);
                    /**
                     * 设置输出
                     */
                    urlConnection.setDoOutput(true);

                    /**
                     * 参数写入
                     */
                    PrintWriter printWriter = new PrintWriter(urlConnection.getOutputStream());
                    printWriter.write(jsonParam.toString());
                    printWriter.flush();

                    //返回值解析
                    parseResponse(urlConnection, listener);

                    printWriter.close();

                } catch (Exception e) {
                    if (listener != null) {
                        if(e instanceof UnknownHostException ||
                                e instanceof ConnectException ||
                                e instanceof TimeoutException ||
                                e instanceof ProtocolException ||
                                e instanceof IOException ||
                                e instanceof EOFException ||
                                e instanceof SSLException ||
                                e instanceof SSLHandshakeException){
                            listener.onResponseError(-4001, "请检测网络");
                        }else{
                            listener.onResponseError(-4000, e.getMessage());
                        }

                    }

                }finally {
                    closeConnection(urlConnection);
                }
            }
        });

    }

    /**
     * 网络请求是否成功
     */
    private static boolean isOK(int responseCode) {
        return responseCode == HttpURLConnection.HTTP_OK;
    }

    /**
     * 参数构建
     * @param params
     * @return
     */
    private static String buildParams(Map<String, Object> params){
        if (null == params || params.isEmpty()) {
            return "";
        }

        StringBuilder paramSB = new StringBuilder();

        boolean isFirst = true;

        for (String key : params.keySet()) {
            if(isFirst) {
                isFirst = false;
            } else {
                paramSB.append("&");
            }

            paramSB.append(key).append("=").append(URLEncoder.encode(String.valueOf(params.get(key))));
        }
        String result = paramSB.toString();
        return result;
    }

    /**
     * 关闭连接
     * @param connection
     */
    private static void closeConnection(HttpURLConnection connection) {
        if (null != connection) {
            connection.disconnect();
        }
    }

    /**
     * 解析response信息
     * @param urlConnection
     * @param listener
     */
    private static void parseResponse(HttpURLConnection urlConnection,
                                      OnHttpRequestListener listener) throws Exception {
        int httpStatus = urlConnection.getResponseCode();
        if (isOK(httpStatus)) {
            String result = streamToString(urlConnection.getInputStream());
            if (listener != null) {
                listener.onResponseSuccess(result);
            }

        } else {
            if (listener != null) {
                listener.onResponseError(httpStatus, urlConnection.getResponseMessage());
            }

        }
    }

    /**
     * 打开一个连接
     * @param baseUrl
     * @return
     * @throws IOException
     */
    private static HttpURLConnection openURLConnection(String baseUrl)
            throws IOException {
        URL url = new URL(baseUrl);
        HttpURLConnection urlConnection = (HttpURLConnection)url.openConnection();
        //添加https的认证
        if (baseUrl.toUpperCase().startsWith("HTTPS")) {
            HttpsURLConnection httpsURLConnection = (HttpsURLConnection) urlConnection;
            httpsURLConnection.setHostnameVerifier(new HttpsHostnameVerifier());
            httpsURLConnection.setSSLSocketFactory(HttpsSSLSocketFactory.factory());
            urlConnection = httpsURLConnection;
        }
        // Workaround for the M release HttpURLConnection not observing the
        // HttpURLConnection.setFollowRedirects() property.
        // https://code.google.com/p/android/issues/detail?id=194495
        urlConnection.setInstanceFollowRedirects(HttpURLConnection.getFollowRedirects());
        //urlConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");

        //设置超时时间
        urlConnection.setConnectTimeout(CONNECT_TIMEOUT);
        urlConnection.setReadTimeout(READ_TIMEOUT);

        //设置连接类型
        urlConnection.setRequestProperty(REQ_PROPERTY_CONNECTION,
                REQ_VALUE_CONNECTION);

        //不使用缓存
        urlConnection.setUseCaches(false);

        return urlConnection;
    }

    /**
     * 流转换为string字符串
     * @param inputStream
     * @return
     * @throws IOException
     */
    private static String streamToString(InputStream inputStream)
            throws IOException {

        BufferedReader br = new BufferedReader(new InputStreamReader(inputStream,
                CHARSET_UTF8));

        StringBuffer sb = new StringBuffer();

        String line = null;

        while ((line = br.readLine()) != null) {
            sb.append(line);
        }

        br.close();

        return sb.toString();

    }
}
